package com.pactera.asmp.server.common.interceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.http.HttpMethod;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import com.pactera.asmp.server.common.annotations.JwtIgnore;
import com.pactera.asmp.server.common.constants.Constants;
import com.pactera.asmp.server.common.constants.DeviceEnum;
import com.pactera.asmp.server.common.constants.ResultCode;
import com.pactera.asmp.server.common.domain.Audience;
import com.pactera.asmp.server.common.exception.CustomException;
import com.pactera.asmp.server.common.utils.JwtTokenUtil;
import com.pactera.asmp.server.dao.UserMapper;
import com.pactera.asmp.server.pojo.User;
import com.pactera.asmp.server.service.RedisServiceImpl;
import com.pactera.asmp.server.shiro.ShiroRealm;

import io.jsonwebtoken.Claims;

/**
 * @ProjectName: tlsserver
 * @Package com.pactera.asmp.server.common.interceptor
 * @ClassName: AuthTokenInterceptor
 * @Description: Token鉴定拦截器
 * @Date 2020/05/30 18:11
 * @Author lvzhiqiang
 * @Version 1.0
 */
public class AuthTokenInterceptor extends HandlerInterceptorAdapter {
    private Logger logger = LoggerFactory.getLogger(AuthTokenInterceptor.class.getSimpleName());

    @Autowired
    private Audience audience;

    @Autowired
    private RedisServiceImpl mRedisService;

    @Autowired
    private StringRedisTemplate redisTemplate;

    @Autowired
    private UserMapper userMapper;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        if (handler instanceof HandlerMethod) {
            HandlerMethod handlerMethod = (HandlerMethod) handler;
            JwtIgnore jwtIgnore = handlerMethod.getMethodAnnotation(JwtIgnore.class);
            if (jwtIgnore != null) {
                return true;
            }
        }

        if (HttpMethod.OPTIONS.toString().equalsIgnoreCase(request.getMethod())) {
            response.setStatus(HttpServletResponse.SC_OK);
            return true;
        }

        final String authHeader = request.getHeader(JwtTokenUtil.AUTH_HEADER_KEY);
        if (StringUtils.isBlank(authHeader) || !authHeader.startsWith(JwtTokenUtil.TOKEN_PREFIX)) {
            logger.info("### Authorization AuthToken 未检测到Token数据:{}, {}",authHeader,request.getRequestURI());
            throw new CustomException(ResultCode.PERMISSION_TOKEN_EXPIRED);
        }

        String token = authHeader.substring(7);
        Claims claims = JwtTokenUtil.parseJWT(token,audience.base64Secret); // 验证token (过期或无效)
        if (null == claims || null == claims.get("uuid") || null == claims.get("channelId")) {
            throw new CustomException(ResultCode.PERMISSION_TOKEN_EXPIRED);
        }
        int uuid = Integer.parseInt(claims.get("uuid", String.class));
        int channelId = claims.get("channelId", Integer.class);
        if(channelId == DeviceEnum.PC_BROWSER.getChannelId()) {
            if (!StringUtils.equals(mRedisService.get(Constants.REDIS_TOKEN_KEY + channelId + ":" + uuid), token)) {
                throw new CustomException(ResultCode.PERMISSION_USER_LOGIN_OTHER_PLACE);
            }
            String authKey = StringUtils.join(ShiroRealm.KEY_SHIRO_PREFIX, this.getClass().getName(), ShiroRealm.KEY_AUTHOR_PREFIX, ":", uuid);
            if(!redisTemplate.hasKey(authKey)) {
                User user = userMapper.selectByPrimaryKey(uuid);
                if(null == user || user.getIsDel()) {
                    throw new CustomException(ResultCode.PERMISSION_USER_DELETE);
                }
            }
        }
        return true;
    }

}
